unit uniHeroAircraft;

interface

uses
  uniEnemyAircraft,
  uniPowerUps,
  uniScreenItem,
  uniDefine,
  gl,
  Classes;

const
  DEATH_SPIKES = 7;
  DEATH_TIME = 50;
type
  { HeroAircraft }

  HeroAircraft = class(ScreenItem)
  public
    heroTex: GLuint;
    bombTex: GLuint;

    gunFlash0: array[0..NUM_HERO_AMMO_TYPES - 1] of Single;
    gunFlash1: array[0..NUM_HERO_AMMO_TYPES - 1] of Single;
    gunActive: array[0..NUM_HERO_AMMO_TYPES - 1] of Boolean;

    epos: array[0..2] of Single;
    size: array[0..1] of Single;
    bound: array[0..1, 0..1] of Single;

    deathCircle: array[0..DEATH_SPIKES - 1, 0..1] of Single;
    deathStereo: Single;

    lives: Integer;
    dontShow: Integer;
    superBomb: Integer;
    scoreStep: Single;
    scoreTarget: Single;

    ammoStock: array[0..NUM_HERO_AMMO_TYPES - 1] of Single;
    gunPause: array[0..NUM_HERO_AMMO_TYPES - 1] of Single;
    gunSwap: Boolean;
    gunTrigger: Boolean;

    damage: Single;
    shields: Single;
    score: Single;

    currentItemIndex: Integer;
    useItemArmed: Single;

    //-- secondary movement
    move: array[0..1] of Single;
    secondaryMove: array[0..1] of Single;

    //-- tip variables
    tipShipPast: Integer;
    tipSuperShield: Integer;

    // game: Global;

    constructor Create;
    destructor Destroy; override;

    procedure moveEvent(x, y: Integer);
    procedure fireGun(temp: Boolean);
    procedure shootGun;
    procedure useItem(index: Integer); overload;
    procedure useItem; overload;
    procedure nextItem; {useItemArmed = 0.0; currentItemIndex = ++currentItemIndex%NUM_HERO_ITEMS;}
    procedure dropBomb;

    procedure doDamage(d: Single);
    procedure ammoDamage(d: Single; vec: array of Single);
    procedure checkForCollisions(fleet: EnemyFleet);
    procedure checkForPowerUps(powerUps: PowerUps);

    function currentItem: Integer; {return currentItemIndex;}
    function itemArmed: Single; {return useItemArmed;}

    function getLives: Integer; {return lives;}
    procedure setLives(Index: Integer);
    function getScore: Single; {return score;}
    procedure addScore(index: Single);
    procedure addLife(score: Boolean = False);
    procedure loseLife;

    procedure startDeath;

    procedure update;
    procedure drawGL;
    procedure reset;
    procedure newGame;
    procedure fullHealth;

    function getAmmoStock(index: Integer): Single; {return ammoStock[index];}
    function getDamage: Single; {return damage;}
    function getShields: Single; {return shields;}
    function isVisible: Boolean; {return not dontShow;}

    function getPos: PSingle; override;
    function getSize(i: Integer): Single; {return size[i];}

    procedure loadTextures;
    procedure deleteTextures;

    procedure setAmmoStock(index: Integer; value: Single);
    procedure deathExplosions;

    procedure drawQuad(szx, szy: Single);
    {
  glBegin(GL_TRIANGLE_STRIP);
   glTexCoord2f(1.0, 0.0); glVertex3f( szx,  szy, 0.0);
   glTexCoord2f(0.0, 0.0); glVertex3f(-szx,  szy, 0.0);
   glTexCoord2f(1.0, 1.0); glVertex3f( szx, -szy, 0.0);
   glTexCoord2f(0.0, 1.0); glVertex3f(-szx, -szy, 0.0);
  glEnd();
    }
  end;


implementation

uses
  PNGLoader,
  uniConfig,
  uniExplosions,
  uniAudio,
  uniGlobal;

{ HeroAircraft }

procedure HeroAircraft.addLife(score: Boolean);
var
  p: array[0..2] of Single;
begin
  p[0] := 10.2;
  p[1] := 0.0;
  p[2] := 25.0;
  p[1] := 7.4 - lives * uniGlobal._hero.size[1];
  _audio.playSound(uniAudio.AddLife, p);
  _explosions.addExplo(uniExplosions.AddLife, P);
  _explosions.addExplo(uniExplosions.AddLife, P, -10);
  _explosions.addExplo(uniExplosions.AddLife, P, -13);

  if score then
  begin
    p[0] := -7.9;
    p[1] := -8.0;
    _audio.playSound(uniAudio.AddLife, p);
    _explosions.addExplo(uniExplosions.PowerBurst, p);
    _explosions.addExplo(uniExplosions.ScoreLife, p, 0);
    _explosions.addExplo(uniExplosions.ScoreLife, p, -3);
    _explosions.addExplo(uniExplosions.ScoreLife, p, -9);
    _explosions.addExplo(uniExplosions.ScoreLife, p, -15);
  end;

  if lives < 9 then
    Inc(lives)
  else
    superBomb := 1;
end;

procedure HeroAircraft.addScore(index: Single);
begin
  if _gameMode <> uniGlobal.HeroDead then
  begin
    score := score + index;
  end;
end;

procedure HeroAircraft.ammoDamage(d: Single; vec: array of Single);
var
  f, a: Single;
begin
  if Boolean(superBomb) then Exit;
  f := d / 50.0;
  secondaryMove[0] := vec[0] * f;
  secondaryMove[1] := vec[1] * f;
  a := 2.0;
  pos[0] := pos[0] + vec[0] * f * a;
  pos[1] := pos[1] + vec[1] * f * a;
  pos[2] := pos[2] + vec[2] * f * a;
end;

procedure HeroAircraft.checkForCollisions(fleet: EnemyFleet);
var
  p: array[0..2] of Single;
  r1, r2: Single;
  diffX, diffY: Single;
  dist: Single;
  power: Single;
  enemy: EnemyAircraft;
begin
  fleet.toFirst;
  while True do
  begin
    enemy := fleet.getShip;
    if not Boolean(enemy) then Break;

    diffX := pos[0] - enemy.pos[0];
    diffY := pos[1] - enemy.pos[1];
    dist := Abs(diffX) + Abs(diffY);
    if (not Boolean(dontShow)) and (dist < enemy.size[0] + size[0]) then
    begin
      //-- damage
      power := -enemy.damage * 0.5;
      if power > 35.0 then power := 35.0;
      if shields > HERO_SHIELDS then
      begin
        power := power * 0.5; // reduce secondary movement when super shields are enabled
        enemy.damage := enemy.damage + 70.0;
      end
      else
      begin
        enemy.damage := enemy.damage + 40.0; // normal collision
      end;

      //-- explosions
      r1 := SRAND * 0.3;
      r2 := SRAND * 0.4;
      p[0] := enemy.pos[0] + r1;
      p[1] := enemy.pos[1] + r2;
      p[2] := enemy.pos[2];
      _explosions.addExplo(EnemyDamage, p);
      p[0] := pos[0] + r1;
      p[1] := pos[1] + 0.2 + r2;
      p[2] := pos[2];
      if shields > 0.0 then
      begin
        _explosions.addExplo(HeroShields, p);
      end
      else
      begin
        _explosions.addExplo(HeroDamage, p);
      end;

      secondaryMove[0] := diffX * power * 0.03;
      secondaryMove[1] := diffY * power * 0.03;
      enemy.secondaryMove[0] := enemy.secondaryMove[0] - diffX * enemy.collisionMove;
      enemy.secondaryMove[1] := enemy.secondaryMove[1] - diffY * (enemy.collisionMove * 0.5);
    end;

    if Boolean(superBomb) then
    begin
      diffX := -enemy.pos[0];
      diffY := -15.0 - enemy.pos[1];
      dist := Sqrt(diffX * diffX + diffY * diffY);
      if ((dist < superBomb * 0.1) and (enemy._type < EnemyBoss00)) or
        (enemy.pos[0] < -11.0) then
      begin
        enemy.damage := enemy.damage + 5000.0;
      end;
      if superBomb > 300 then superBomb := 0;
    end;
  end;

  if Boolean(superBomb) then superBomb := superBomb + 2;
end;

procedure HeroAircraft.checkForPowerUps(powerUps: PowerUps);
var
  dist: Single;
  stock: Single;
  pwrUp: uniPowerUps.PowerUp;
  delUp: uniPowerUps.PowerUp;

  p0, v0: array[0..2] of Single;
  clr: array[0..3] of Single;
begin
  if Boolean(dontShow) then Exit;

  if score > scoreTarget then
  begin
    scoreTarget := scoreTarget + scoreStep;
    addLife(True);
  end;

  p0[0] := 10.4;
  p0[1] := -8.30;
  p0[2] := 25.0;

  v0[0] := 0.0;
  v0[1] := 0.08;
  v0[2] := 0.0;

  clr[0] := 1.0;
  clr[1] := 1.0;
  clr[2] := 1.0;
  clr[3] := 1.0;

  if _gameMode = Game then
  begin
    pwrUp := powerUps.getFirst;
  end
  else
  begin
    pwrUp := nil;
  end;

  while Boolean(pwrUp) do
  begin
    dist := Abs(pos[0] - pwrUp.pos[0]) + Abs(pos[1] - pwrUp.pos[1]);
    if dist < size[1] then
    begin
      _audio.playSound(PowerUp, Pos);
      case pwrUp._type of
        uniPowerUps.Shields:
          begin
            if shields < HERO_SHIELDS then shields := HERO_SHIELDS;
            _statusDisplay.setShieldAlpha(5.0);
            p0[0] := -10.4;
            _explosions.addElectric(p0, v0, clr, 0);
            _explosions.addElectric(p0, v0, clr, -1);
            _explosions.addElectric(p0, v0, clr, -3);
            _explosions.addElectric(p0, v0, clr, -4);
          end;
        uniPowerUps.SuperShields:
          begin
            Inc(uniGlobal.tipSuperShield);
            damage := damage - shields;
            if damage < HERO_DAMAGE then damage := HERO_DAMAGE;
            shields := HERO_SHIELDS * 2;
            _statusDisplay.setDamageAlpha(5.0);
            _statusDisplay.setShieldAlpha(5.0);
            p0[0] := -10.4;
            _explosions.addElectric(p0, v0, clr, 0);
            _explosions.addElectric(p0, v0, clr, -1);
            _explosions.addElectric(p0, v0, clr, -3);
            _explosions.addElectric(p0, v0, clr, -4);
            _explosions.addElectric(p0, v0, clr, -10);
            _explosions.addElectric(p0, v0, clr, -11);
            _explosions.addElectric(p0, v0, clr, -13);
            _explosions.addElectric(p0, v0, clr, -14);

            p0[0] := -10.4;
            _explosions.addElectric(p0, v0, clr, 0);
            _explosions.addElectric(p0, v0, clr, -1);
            _explosions.addElectric(p0, v0, clr, -3);
            _explosions.addElectric(p0, v0, clr, -4);
            _explosions.addElectric(p0, v0, clr, -10);
            _explosions.addElectric(p0, v0, clr, -11);
            _explosions.addElectric(p0, v0, clr, -13);
            _explosions.addElectric(p0, v0, clr, -14);
          end;
        uniPowerUps.Repair:
          begin
            _statusDisplay.setDamageAlpha(5.0);
            damage := HERO_DAMAGE;
            p0[0] := 10.4;
            _explosions.addElectric(p0, v0, clr, 0);
            _explosions.addElectric(p0, v0, clr, -1);
            _explosions.addElectric(p0, v0, clr, -3);
            _explosions.addElectric(p0, v0, clr, -4);
          end;
        uniPowerUps.HeroAmmo00:
          begin
            addScore(100.0);
            stock := ammoStock[0] + pwrUp.power * AMMO_REFILL;
            if stock > AMMO_REFILL then stock := AMMO_REFILL;
            setAmmoStock(0, stock);
          end;
        uniPowerUps.HeroAmmo01:
          begin
            addScore(100.0);
            stock := ammoStock[1] + pwrUp.power * AMMO_REFILL;
            if stock > AMMO_REFILL then stock := AMMO_REFILL;
            setAmmoStock(1, stock);
          end;
        uniPowerUps.HeroAmmo02:
          begin
            addScore(100.0);
            stock := ammoStock[2] + pwrUp.power * AMMO_REFILL;
            if stock > AMMO_REFILL then stock := AMMO_REFILL;
            setAmmoStock(2, stock);
          end;
      end;
      _explosions.addExplo(PowerBurst, pwrUp.pos);
      delUp := pwrUp;
      pwrUp := pwrUp.next;
      powerUps.remove(delUp);
    end
    else
    begin
      pwrUp := pwrUp.next;
    end;
  end;
end;

constructor HeroAircraft.Create;
begin
  inherited Create(ItemHero);
  // game = Global::getInstance();
  size[0] := 0.7;
  size[1] := 0.85;

  superBomb := 0;
  dontShow := 0;
  lives := 4;
  score := 0.0;

  bound[0][0] := -10.0;
  bound[0][1] := 10.0;
  bound[1][0] := -7.5;
  bound[1][1] := 7.5;

  scoreStep := 50000.0;
  scoreTarget := scoreStep;

  currentItemIndex := 0;
  useItemArmed := 0.0;

  loadTextures;

  reset;
end;

function HeroAircraft.currentItem: Integer;
begin
  Result := currentItemIndex;
end;

procedure HeroAircraft.deathExplosions;
var
  i: Integer;
  r: Single;
  p: array[0..2] of Single;
  w, skip: Integer;

  rnd, a, s: Double;
begin
  p[0] := 0.0;
  p[1] := -0.5;
  p[2] := pos[2];

  deathStereo := 5.0;
  p[0] := -deathStereo;
  _audio.playSound(Explosion, p);
  _audio.playSound(Explosion, p, -45);
  p[0] := deathStereo;
  _audio.playSound(Explosion, p);
  _audio.playSound(Explosion, p, -20);
  p[0] := 0.0;
  _audio.playSound(ExploBig, p);
  _audio.playSound(ExploPop, p);

  //-- Caclulate radius
  for i := 0 to DEATH_SPIKES - 1 do
  begin
    rnd := FRAND;
    a := rnd + 2.0 * M_PI * (i / DEATH_SPIKES);
    s := 0.5 + 0.5 * FRAND;
    deathCircle[i][0] := sin(a) * s;
    deathCircle[i][1] := cos(a) * s;
    p[0] := pos[0] + deathCircle[i][0];
    p[1] := pos[1] + deathCircle[i][1];
    p[2] := pos[2];
    _explosions.addExplo(EnemyDestroyed, p);
  end;

  //-- Set up explosions
  for i := 0 to DEATH_TIME - 1 do
  begin
    w := i mod DEATH_SPIKES;
    skip := 1 + Round(3.0 * FRAND);
    p[2] := pos[2];
    if i < DEATH_TIME - DEATH_SPIKES then
    begin
      if not Boolean(i mod skip) then
      begin
        r := 1.25 + 4.0 * (i / DEATH_TIME);
        p[0] := pos[0] + deathCircle[w][0] * r;
        p[1] := pos[1] + deathCircle[w][1] * r;
        _explosions.addExplo(EnemyDestroyed, p, -i);
      end;
    end
    else
    begin
      p[0] := pos[0] + deathCircle[w][0];
      p[1] := pos[1] + deathCircle[w][1];
      _explosions.addExplo(EnemyDestroyed, p, -i);
    end;
    if not Boolean(i mod 21) then
    begin
      deathStereo := -deathStereo * 1.5;
      p[0] := deathStereo;
      p[1] := -5.0;
      _audio.playSound(Explosion, p, -i);
    end;
  end;
end;

procedure HeroAircraft.deleteTextures;
begin
  glDeleteTextures(1, @heroTex);
  glDeleteTextures(1, @bombTex);
  heroTex := 0;
  bombTex := 0;
end;

destructor HeroAircraft.Destroy;
begin
  deleteTextures;
  inherited;
end;

procedure HeroAircraft.doDamage(d: Single);
begin
  if Boolean(superBomb) then Exit;

  if shields > HERO_SHIELDS then
  begin
    shields := shields - d * 0.25;
    _explosions.addExplo(HeroShields, pos);
    _statusDisplay.setShieldAlpha(1.0);
  end
  else
  begin
    if shields > 0.0 then
    begin
      shields := shields - d * 0.8;
      damage := damage + d * 0.2;
      if shields < 0.0 then shields := 0.0;
      _explosions.addExplo(HeroShields, pos);
      _statusDisplay.setShieldAlpha(1.0);
      _statusDisplay.setDamageAlpha(1.0);
    end
    else
    begin
      damage := damage + d;
      _statusDisplay.setDamageAlpha(1.0);
    end;
  end;

  if damage > 0.0 then
  begin
    damage := 0.0;
    Dec(lives);
    startDeath;
  end;
end;

procedure HeroAircraft.drawGL;
var
  s: Single;
begin
  //-- draw hero
  glPushMatrix;
  glTranslatef(pos[0], pos[1], pos[2]);
  if not Boolean(dontShow) then
  begin
    glColor4f(1.0, 1.0, 1.0, 1.0);
    glBindTexture(GL_TEXTURE_2D, heroTex);
    drawQuad(size[0], size[1]);
  end
  else
  begin
    Dec(dontShow);
  end;

  //-- draw super shields in StatusDisplay to get better blend mode..
  glPopMatrix;

  if Boolean(superBomb) then
  begin
    s := superBomb * 0.1;
    glBlendFunc(GL_SRC_ALPHA, GL_ONE);
    glBindTexture(GL_TEXTURE_2D, bombTex);
    glPushMatrix;
    glTranslatef(0.0, -15.0, HERO_Z);
    glRotatef(IRAND, 0.0, 0.0, 1.0);
    drawQuad(s, s);
    glPopMatrix;
    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
  end;
end;

procedure HeroAircraft.drawQuad(szx, szy: Single);
begin
  glBegin(GL_TRIANGLE_STRIP);
  glTexCoord2f(1.0, 0.0); glVertex3f(szx, szy, 0.0);
  glTexCoord2f(0.0, 0.0); glVertex3f(-szx, szy, 0.0);
  glTexCoord2f(1.0, 1.0); glVertex3f(szx, -szy, 0.0);
  glTexCoord2f(0.0, 1.0); glVertex3f(-szx, -szy, 0.0);
  glEnd;
end;

procedure HeroAircraft.dropBomb;
begin

end;

procedure HeroAircraft.fireGun(temp: Boolean);
begin
  if Boolean(dontShow) then Exit;

  if temp and (_gameMode <> uniGlobal.HeroDead) then
  begin
    gunTrigger := True;
    gunPause[0] := 0;
    if Boolean(gunActive[1]) then
    begin
      if gunPause[1] < 0 then
      begin
        gunPause[1] := 0;
      end;
    end;

    if Boolean(gunActive[2]) then
    begin
      if gunPause[2] < 0 then
      begin
        gunPause[2] := 0;
      end;
    end;
  end
  else
  begin
    gunTrigger := False;
    gunPause[0] := -1;
  end;

end;

procedure HeroAircraft.fullHealth;
var
  p0, v0: array[0..2] of Single;
  clr: array[0..3] of Single;
begin
  damage := HERO_DAMAGE;
  shields := HERO_SHIELDS;

  p0[0] := 10.4;
  p0[1] := -8.30;
  p0[2] := 25.0;

  v0[0] := 0.0;
  v0[1] := 0.08;
  v0[2] := 0.0;

  clr[0] := 1.0;
  clr[1] := 1.0;
  clr[2] := 1.0;
  clr[3] := 1.0;


  p0[0] := -10.4;
  _explosions.addElectric(p0, v0, clr, 0);
  _explosions.addElectric(p0, v0, clr, 0);
  _explosions.addElectric(p0, v0, clr, -1);
  _explosions.addElectric(p0, v0, clr, -3);
  _explosions.addElectric(p0, v0, clr, -4);
  p0[0] := 10.4;
  _explosions.addElectric(p0, v0, clr, 0);
  _explosions.addElectric(p0, v0, clr, 0);
  _explosions.addElectric(p0, v0, clr, -1);
  _explosions.addElectric(p0, v0, clr, -3);
  _explosions.addElectric(p0, v0, clr, -4);
  secondaryMove[0] := 0.0;
  secondaryMove[1] := 0.0;
  gunTrigger := false;
  gunSwap := false;
end;

function HeroAircraft.getAmmoStock(index: Integer): Single;
begin
  Result := ammoStock[index];
end;

function HeroAircraft.getDamage: Single;
begin
  Result := damage;
end;

function HeroAircraft.getLives: Integer;
begin
  Result := lives;
end;

function HeroAircraft.getPos: PSingle;
begin
  epos[0] := pos[0];
  epos[1] := pos[1];
  epos[2] := pos[2];
  Result := @epos;
end;

function HeroAircraft.getScore: Single;
begin
  Result := score;
end;

function HeroAircraft.getShields: Single;
begin
  Result := shields;
end;

function HeroAircraft.getSize(i: Integer): Single;
begin
  Result := size[i];
end;

function HeroAircraft.isVisible: Boolean;
begin
  Result := not Boolean(dontShow);
end;

function HeroAircraft.itemArmed: Single;
begin
  Result := useItemArmed;
end;

procedure HeroAircraft.loadTextures;
begin
  LoadTexture('png/hero.png', heroTex);
  LoadTexture('png/superBomb.png', bombTex);
end;

procedure HeroAircraft.loseLife;
var
  p: array[0..2] of Single;
begin
  p[0] := 10.2;
  p[1] := 0.0;
  p[2] := 25.0;
  //-- this has to be in sync w/ StatusDisplay positions...
  Dec(lives);
  p[1] := 7.4 - lives * _hero.size[1];

  if lives > -2 then
  begin
    _audio.playSound(uniAudio.LoseLife, p);
    _explosions.addExplo(uniExplosions.LoseLife, p, 0, 1.5);
    _explosions.addExplo(uniExplosions.LoseLife, p, -10, 1.5);
    _explosions.addExplo(uniExplosions.LoseLife, p, -13, 1.5);
    _explosions.addExplo(uniExplosions.PowerBurst, p);
  end;

  if (lives < 0) and (_gameMode <> HeroDead) then
  begin
    damage := 0;
    shields := 0;
    startDeath;
  end;
end;

procedure HeroAircraft.moveEvent(x, y: Integer);
var
  _config: Config;
  game: Global;
begin
  _config := uniConfig.instance;
  game := uniGlobal.instance;
  if (_gameMode <> uniGlobal.HeroDead) and (not game.game_pause) then
  begin
    pos[0] := pos[0] + x * _config.mouseSpeed;
    pos[1] := pos[1] + -y * _config.mouseSpeed;
    if (pos[0] < bound[0][0]) then
      pos[0] := bound[0][0]
    else if (pos[0] > bound[0][1]) then
      pos[0] := bound[0][1];
    if (pos[1] < bound[1][0]) then pos[1] := bound[1][0]
    else if (pos[1] > bound[1][1]) then pos[1] := bound[1][1];
  end;
end;

procedure HeroAircraft.newGame;
begin
  score := 0;
  superBomb := 0;
  reset;
end;

procedure HeroAircraft.nextItem;
begin
  useItemArmed := 0.0;
  currentItemIndex := (currentItemIndex + currentItemIndex) mod NUM_HERO_ITEMS;
end;

procedure HeroAircraft.reset;
var
  i: Integer;
begin
  pos[0] := 0.0;
  pos[1] := -3.0;
  pos[2] := HERO_Z;
  dontShow := 0;
  damage := HERO_DAMAGE;
  shields := HERO_SHIELDS;
  currentItemIndex := 0;
  secondaryMove[0] := 0.0;
  secondaryMove[1] := 0.0;

  for i := 0 to NUM_HERO_AMMO_TYPES - 1 do
  begin
    gunPause[i] := -1;
    ammoStock[i] := 0;
    gunActive[i] := false;
    gunFlash0[i] := 0.0;
    gunFlash1[i] := 0.0;
  end;
  gunTrigger := false;
  gunSwap := false;
end;

procedure HeroAircraft.setAmmoStock(index: Integer; value: Single);
var
  i: Integer;
begin
  if (index >= 0) and (index < NUM_HERO_AMMO_TYPES) then
  begin
    _statusDisplay.setAmmoAlpha(1.0);
    gunPause[index] := 1;
    gunActive[index] := true;
    ammoStock[index] := value;
  end;
end;

procedure HeroAircraft.setLives(Index: Integer);
begin
  if Index > 9 then Index := 9;
  lives := Index;
end;

procedure HeroAircraft.shootGun;
var
  p: array[0..2] of Single;
  i: Integer;
begin
  p[0] := 0.0;
  p[1] := 0.0;
  p[2] := pos[2];

  if gunPause[0] <= 0 then
  begin
    gunPause[0] := 5;

    p[0] := pos[0] + 0.3;
    p[1] := pos[1] + 0.8;
    _heroAmmo.addAmmo(0, p);
    p[0] := pos[0] - 0.3;
    _heroAmmo.addAmmo(0, p);
    if Boolean(gunActive[0]) then
    begin
      p[0] := pos[0] + 0.45;
      p[1] := pos[1] + 0.2;
      _heroAmmo.addAmmo(0, p);
      p[0] := pos[0] - 0.45;
      _heroAmmo.addAmmo(0, p);
      ammoStock[0] := ammoStock[0] - 0.5;
    end;
    //if (currentItemIndex = 1) and Boolean(Round(useItemArmed)) then // double fire
    if (currentItemIndex = 1) and (useItemArmed <> 0) then // double fire
    begin
      p[0] := pos[0] + 0.37;
      p[1] := pos[1] + 0.6;
      _heroAmmo.addAmmo(0, p);
      p[0] := pos[0] - 0.37;
      _heroAmmo.addAmmo(0, p);
      if Boolean(gunActive[0]) then
      begin
        p[0] := pos[0] + 0.52;
        p[1] := pos[1];
        _heroAmmo.addAmmo(0, p);
        p[0] := pos[0] - 0.52;
        _heroAmmo.addAmmo(0, p);
        ammoStock[0] := ammoStock[0] - 0.75;
      end;
    end;
  end;

  if Boolean(gunActive[1]) and (gunPause[1] <= 0.0) then
  begin
    gunPause[1] := 25;
    p[0] := pos[0];
    p[1] := pos[1] + 1.1;
    _heroAmmo.addAmmo(1, p);
    ammoStock[1] := ammoStock[1] - 1.5;
    //if (currentItemIndex = 1) and Boolean(Round(useItemArmed)) then // double fire
    if (currentItemIndex = 1) and (useItemArmed <> 0) then // double fire
    begin
      p[1] := p[1] - 0.2;
      p[0] := pos[0] + 0.09;
      _heroAmmo.addAmmo(1, p);
      p[0] := pos[0] - 0.09;
      _heroAmmo.addAmmo(1, p);
      ammoStock[1] := ammoStock[1] - 4.5;
    end;
  end;

  if Boolean(gunActive[2]) and (gunPause[2] <= 0.0) then
  begin
    gunSwap := not gunSwap;
    gunPause[2] := 5;
    p[1] := pos[1] + 0.4;
    if gunSwap then
    begin
      p[0] := pos[0] + 0.7;
      _heroAmmo.addAmmo(2, p);
    end
    else
    begin
      p[0] := pos[0] - 0.7;
      _heroAmmo.addAmmo(2, p);
    end;
    ammoStock[2] := ammoStock[2] - 1.5;
    //if (currentItemIndex = 1) and Boolean(Round(useItemArmed)) then // double fire
    if (currentItemIndex = 1) and (useItemArmed <> 0) then // double fire
    begin
      if gunSwap then
      begin
        p[0] := pos[0] + 0.85;
        p[1] := p[1] - 0.75;
        _heroAmmo.addAmmo(2, p);
      end
      else
      begin
        p[0] := pos[0] - 0.85;
        p[1] := p[1] - 0.75;
        _heroAmmo.addAmmo(2, p);
      end;
      ammoStock[2] := ammoStock[2] - 3.5;
    end;
  end;

  //-- clean up gun active
  for i := 0 to NUM_HERO_AMMO_TYPES - 1 do
  begin
    if ammoStock[i] < 0.0 then
    begin
      ammoStock[i] := 0.0;
      gunActive[i] := False;
    end;
  end;

end;

procedure HeroAircraft.startDeath;
begin
  deathExplosions;
  if lives < 0 then
  begin
    fireGun(False);
    uniGlobal.heroDeath := DEATH_TIME;
    _gameMode := HeroDead;
    dontShow := -1;
  end
  else
  begin
    superBomb := 1;
    reset;
    dontShow := 130;
  end;
end;

procedure HeroAircraft.update;
var
  i: Integer;
  flash, pause, s: Single;
begin
  if dontShow > 1 then
  begin
    pos[0] := cos(uniglobal.frame * 0.02) * 9.0;
    pos[1] := 4.0 + sin(uniglobal.frame * 0.07) * 2.0;
  end
  else
  begin
    if dontShow = 1 then
    begin
      pos[0] := 0.0;
      pos[1] := -3.0;
    end;
  end;
  //-- Gun flashes are drawn in StatusDisplay
  if gunTrigger then shootGun;
  for i := 0 to NUM_HERO_AMMO_TYPES - 1 do
  begin
    if gunPause[i] >= 0 then gunPause[i] := gunPause[i] - uniglobal.speedAdj;
    if gunTrigger then
    begin
      case i of
        0:
          begin
            flash := 5.0 / uniglobal.speedAdj;
            pause := gunPause[i] / uniglobal.speedAdj;
            gunFlash0[i] := (flash - pause) / flash;
            if gunActive[i] then
              gunFlash1[i] := (flash - pause) / flash
            else
              gunFlash1[i] := 0.0;
          end;
        1:
          begin
            flash := 10.0 / uniglobal.speedAdj;
            pause := gunPause[i] / uniglobal.speedAdj;
            if gunActive[i] and (gunPause[i] < flash) then
              gunFlash0[i] := (flash - pause) / flash
            else
              gunFlash0[i] := 0.0;
          end;
        2:
          begin
            flash := 5.0 / uniglobal.speedAdj;
            pause := gunPause[i] / uniglobal.speedAdj;
            if gunActive[i] then
            begin
              if gunPause[i] < flash then
              begin
                if gunSwap then
                begin
                  gunFlash0[i] := (flash - pause) / flash;
                  gunFlash1[i] := 0.0;
                end
                else
                begin
                  gunFlash0[i] := 0.0;
                  gunFlash1[i] := (flash - pause) / flash;
                end;
              end;
            end
            else
            begin
              gunFlash0[i] := 0.0;
              gunFlash1[i] := 0.0;
            end;
          end;
      end;
    end
    else
    begin
      if gunFlash0[i] > 0.0 then gunFlash0[i] := gunFlash0[i] - 0.075 * uniglobal.speedAdj
      else gunFlash0[i] := 0.0;
      if gunFlash1[i] > 0.0 then gunFlash1[i] := gunFlash1[i] - 0.075 * uniglobal.speedAdj
      else gunFlash1[i] := 0.0;
    end;
  end;
  //-- decrement item activation
  case currentItemIndex of
    0: // self destruct
      useItemArmed := useItemArmed - 0.02;
    1:
      //if Boolean(Round(useItemArmed)) then doDamage(1);
      if (useItemArmed <> 0) then doDamage(1);
  end;
  if useItemArmed < 0.0 then useItemArmed := 0.0;
  //-- decrement supershields
  if shields >= HERO_SHIELDS then
  begin
    shields := shields - 0.15 * uniglobal.speedAdj;
  end;
  s := (1.0 - uniglobal.speedAdj) + (uniglobal.speedAdj * 0.8);
  secondaryMove[0] := secondaryMove[0] * s;
  secondaryMove[1] := secondaryMove[1] * s;
  pos[0] := pos[0] + secondaryMove[0] * uniglobal.speedAdj;
  pos[1] := pos[1] + secondaryMove[1] * uniglobal.speedAdj;
  moveEvent(0, 0);
end;

procedure HeroAircraft.useItem;
var
  game: Global;
  v: array[0..2] of Single;
  pwrUp: uniPowerUps.PowerUp;
  i: Integer;
begin
  game := uniGlobal.instance;
  if (uniglobal._gameMode = uniGlobal.Game) and (not Boolean(superBomb)) and (not game.game_pause) then
  begin
    //if not Boolean(Round(useItemArmed)) then
    if not (useItemArmed <> 0) then
    begin
      useItemArmed := 1.0;
    end
    else
    begin
      useItemArmed := 0.0;
      //float v[3] := begin 0.0, 0.7, 0.0 end;;
      v[0] := 0.0;
      v[1] := 0.7;
      v[2] := 0.0;
      case currentItemIndex of
        0: // self destruct
          begin
            for i := 0 to NUM_HERO_AMMO_TYPES - 1 do
            begin
              //eject all ammo - return remaining ammo to uniglobal.powerUps
              if ammoStock[i] > 1.0 then
              begin
                v[0] := SRAND * 0.15;
                v[1] := 0.1 + FRAND * 0.1;
                //pwrUp := new PowerUp( (PowerUps::Type)(i+(int)PowerUps::HeroAmmo00), pos, (ammoStock[i]/AMMO_REFILL), v);
                pwrUp := uniPowerUps.PowerUp.Create(uniPowerUps.HeroAmmo00, pos, v, (ammoStock[i] / AMMO_REFILL));
                uniglobal._powerUps.addPowerUp(pwrUp);
              end;
            end;
            damage := 0.0;
            shields := 0.0;
            Dec(lives);
            startDeath;
          end;
      end;
    end;
  end;
end;

procedure HeroAircraft.useItem(index: Integer);
begin
  if currentItemIndex = index then
  begin
    useItem;
  end
  else
  begin
    if (index < NUM_HERO_ITEMS) and (index >= 0) then
    begin
      currentItemIndex := index;
      useItemArmed := 0.0;
      useItem;
    end;
  end;
end;

end.

